using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Model;
using Me.Prettyprint.Cassandra.Model.Thrift;
using Me.Prettyprint.Cassandra.Serializers;
using Me.Prettyprint.Cassandra.Service;
using Me.Prettyprint.Cassandra.Utils;
using Me.Prettyprint.Hector.Api;
using Me.Prettyprint.Hector.Api.Beans;
using Me.Prettyprint.Hector.Api.Factory;
using Me.Prettyprint.Hector.Api.Mutation;
using Me.Prettyprint.Hector.Api.Query;
using Thrift;

namespace Me.Prettyprint.Cassandra.Service.Template
{
    /// <summary>
    ///  This provides an interface of updating a specified row, most likely with the
    ///  contents of an object. This would likely by implemented as an anonymous inner
    ///  class with access to a final object in scope. It would update the given row
    ///  with the object's data.
    ///  
    ///  For more complex behaviour, subclasses should implementat update() to simply make
    ///  consecutive calls to various set****() methods which already have the
    ///  contextual information they need to update the correct row.
    ///  
    ///  The downside of this approach is that the updater is essentially stateful and
    ///  cannot be used concurrently. The alternative is to pass an object in to
    ///  update() as a parameter with the setter methods, leaving the updater to be
    ///  stateless.
    /// </summary>
    /// <typeparam name="K"></typeparam>
    /// <typeparam name="N"></typeparam>
    public class ColumnFamilyUpdater<K,N> : AbstractTemplateUpdater<K,N>
	{
        public ColumnFamilyUpdater(ColumnFamilyTemplate<K, N> template, ColumnFactory columnFactory) : base(template, columnFactory, template.CreateMutator())
        {
        }
        public ColumnFamilyUpdater(ColumnFamilyTemplate<K, N> template, ColumnFactory columnFactory, Mutator<K> mutator) : base(template, columnFactory, mutator)
        {
        }
        public void DeleteColumn(N columnName)
        {
            CurrentMutator.AddDeletion(GetCurrentKey(), Template.ColumnFamily,
                columnName, Template.TopSerializer, Clock);
        }
        public void SetString(N columnName, string value)
        {
            AddInsertion(columnName, value, StringSerializer.Instance, Ttl);
        }
        public void SetString(N columnName, string value, int ttl)
        {
            AddInsertion(columnName, value, StringSerializer.Instance, ttl);
        }
        public void SetUUID(N columnName, Guid value)
        {
            AddInsertion(columnName, value, UUIDSerializer.Instance, Ttl);
        }
        public void SetUUID(N columnName, Guid value, int ttl)
        {
            AddInsertion(columnName, value, UUIDSerializer.Instance, ttl);
        }
        public void SetShort(N columnName, short value)
        {
            AddInsertion(columnName, value, ShortSerializer.Instance, Ttl);
        }
        public void SetLong(N columnName, long value)
        {
            AddInsertion(columnName, value, LongSerializer.Instance, Ttl);
        }
        public void SetLong(N columnName, long value, int ttl)
        {
            AddInsertion(columnName, value, LongSerializer.Instance, ttl);
        }
        public void SetInteger(N columnName, int value)
        {
            AddInsertion(columnName, value, IntegerSerializer.Instance, Ttl);
        }
        public void SetInteger(N columnName, int value, int ttl)
        {
            AddInsertion(columnName, value, IntegerSerializer.Instance, ttl);
        }
        public void SetFloat(N columnName, float value)
        {
            AddInsertion(columnName, value, FloatSerializer.Instance, Ttl);
        }
        public void SetFloat(N columnName, float value, int ttl)
        {
            AddInsertion(columnName, value, FloatSerializer.Instance, ttl);
        }
        public void SetDouble(N columnName, double value)
        {
            AddInsertion(columnName, value, DoubleSerializer.Instance, Ttl);
        }
        public void SetDouble(N columnName, double value, int ttl)
        {
            AddInsertion(columnName, value, DoubleSerializer.Instance, ttl);
        }
        public void SetBoolean(N columnName, bool value)
        {
            AddInsertion(columnName, value, BooleanSerializer.Instance, Ttl);
        }
        public void SetBoolean(N columnName, bool value, int ttl)
        {
            AddInsertion(columnName, value, BooleanSerializer.Instance, ttl);
        }
        public void SetByteArray(N columnName, byte[] value)
        {
            AddInsertion(columnName, value, BytesArraySerializer.Instance, Ttl);
        }
        public void SetByteArray(N columnName, byte[] value, int ttl)
        {
            AddInsertion(columnName, value, BytesArraySerializer.Instance, ttl);
        }
        public void SetByteBuffer(N columnName, ByteBuffer value)
        {
            AddInsertion(columnName, value, ByteBufferSerializer.Instance, Ttl);
        }
        public void SetByteBuffer(N columnName, ByteBuffer value, int ttl)
        {
            AddInsertion(columnName, value, ByteBufferSerializer.Instance, Ttl);
        }
        public void SetDate(N columnName, DateTime value)
        {
            AddInsertion(columnName, value, DateSerializer.Instance, Ttl);
        }
        public void SetFloat<V>(N columnName, float value)
        {
            AddInsertion(columnName, value, FloatSerializer.Instance, Ttl);
        }
        public void SetComposite<V>(N columnName, Composite composite)
        {
            AddInsertion(columnName, composite, CompositeSerializer.Instance, Ttl);
        }
        public void SetDynamicComposite<V>(N columnName, DynamicComposite composite)
        {
            AddInsertion(columnName, composite, DynamicCompositeSerializer.Instance, Ttl);
        }
        public void SetBigDecimal<V>(N columnName, System.Numerics.BigDecimal value)
        {
            AddInsertion(columnName, value, BigDecimalSerializer.Instance, Ttl);
        }
        public void SetBigInteger<V>(N columnName, System.Numerics.BigInteger value)
        {
            AddInsertion(columnName, value, BigIntegerSerializer.Instance, Ttl);
        }
        public void SetValue<V>(N columnName, V value, Serializer<V> serializer)
        {
            AddInsertion(columnName, value, serializer, Ttl);
        }
        public void SetValue<V>(N columnName, V value, Serializer<V> serializer, int ttl)
        {
            AddInsertion(columnName, value, serializer, ttl);
        }
        private void AddInsertion<V>(N columnName, V value, Serializer<V> valueSerializer, int ttl)
        {
            HColumn<N,V> column = ColumnFactory.CreateColumn(columnName, value, Clock, Template.TopSerializer, valueSerializer);
            if(ttl > DEF_TTL)
            {
                column.SetTtl(ttl);
            }
            CurrentMutator.AddInsertion(GetCurrentKey(), Template.ColumnFamily, column);
        }
        public void SetColumn<V>(HColumn<N, V> column)
        {
            CurrentMutator.AddInsertion(GetCurrentKey(), Template.ColumnFamily, column);
        }
	}
}